home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
288_01
/
mstr_env.txt
< prev
next >
Wrap
Text File
|
1989-05-23
|
11KB
|
217 lines
Scott Robert Ladd
302 North 12th St.
Gunnison, CO 81230
(303) 641-6438
1700 words
350 source lines
Accessing the Master Environment in MS-DOS
by Scott Robert Ladd
When writing software for MS-DOS, a programmer often
confronts what seem to be artificial restrictions on what can and
can't be done. Some of the utilities provided with MS-DOS can
accomplish tasks which the programmer cannot duplicate through
documented features of the operating system. This article
attempts to lift the shroud from one of MS-DOS's hidden secrets
by providing functions for accessing the master copy of the MS-
DOS environment. It is assumed that the reader is familiar with
the 8088's segmented memory model and the way in which MS-DOS
functions are accessed via software interrupts.
The environment is a collection of text variables maintained
by COMMAND.COM. These variables consist of a name and an
associated text string. Environment variables are used for a wide
variety of purposes by both the operating system and application
programs. Common examples of environment variables include
COMSPEC (which stores the pathname of the MS-DOS shell), PROMPT
(the prompt definition string), and PATH (containing the list of
directories to be searched for executable files). Some
environment variables are maintain through special commands, as
in the preceding examples. Other environment variables are stored
using the internal MS-DOS command SET. Programmers are well aware
of environment variables; most compilers use them for locating
header files, libraries, and compiler components.
Every program in MS-DOS has its own environment. A program
which executes another program is known as a "parent", while the
program it executed is called a "child". A child, in turn, can
also be the parent of other programs. A child process inherits a
copy of the environment associated with its parent. Changes made
by the child to its copy of the environment have no affect on the
parent's copy -- and vice versa.
The MS-DOS command shell, COMMAND.COM, is the ultimate
parent of all resident programs, since it is the first program
loaded. At boot time, COMMAND.COM allocates a block of memory
into which it stores the master environment variables. Since most
programs are executed from the COMMAND.COM prompt, it is the
direct parent of most programs. However, many programs are
capable of running other programs directly, and additional copies
of COMMAND.COM can be resident simultaneously as well.
When a program is loaded by MS-DOS, a 256-byte header is
created for it. This header contains important operating system
data, and is called the Program Segment Prefix (PSP). A program
can locate the copy of its local environment via a segment
pointer stored at offset 0x2C within the PSP. Most MS-DOS
implementations of C provide the function getenv(), which
retrieves the value of an environment variable from the local
environment. Some compilers also offer a putenv() function, which
stores a variable in the local environment.
Putenv() is not particularly useful. When a local
environment is created, it's size is only slightly larger than
that required to hold all of the existing variables in the parent
environment. A copy of the environment cannot be expanded, so
there is very little room to add new variables. Any changes to a
local environment are transient; when a program terminates, its
local environment vanishes too. In addition, changing the local
copy of the environment is solely useful if child programs are to
be executed, since they are the only ones which will see new or
changed values.
It would be useful to make changes to the master
environment. A program could pass along information to other
programs through master environment variables. A program could
store status information for future incarnations of itself in the
master environment. A TSR can use the variables in the global
environment to ensure that it is aware of any changes since it
was executed. The problem is that MS-DOS does not provide any
documented way of accessing the master environment. In order to
work with the master environment, we must enter the world of
undocumented features. I'll begin with a short discussion of MS-
DOS memory management.
MS-DOS organizes memory into blocks. Each block is prefaced
by a 16-byte paragraph-aligned header called the Memory Control
Block, or MCB for short. The MCB contains 3 pieces of
information: a status indicator, the segment of the owning
program's PSP, and the length of the block. The status indicator
is a byte which contains either the character 'M' (indicating
that it is a member of the MCB chain) or a 'Z' (denoting this as
the last MCB in the chain). The length of the block is stored as
a number of 16-byte paragraphs.
Many popular public domain programs can use the chain of
MCBs to display a map of programs and data resident in memory.
The first MCB can be located through an undocumented INT 0x21
service of MS-DOS, 0x52. Function 0x52 returns a pointer (in
ES:BX) to an internal table of MS-DOS values. Immediately
preceding this table is the segment address of the first MCB.
Starting with the first MCB, a program can follow the chain of
memory blocks by a simple formula: add the size of a block plus 1
to the segment address of the current block to calculate the
segment of the next MCB in the chain.
The initial copy of COMMAND.COM creates a memory segment
which will contain the master environment. Usually, this is
located in the memory block directly after the one which contains
COMMAND.COM, and the environment pointer in COMMAND.COM's PSP is
set to 0. Beginning with MS-DOS version 3.3, however, the
location of the environment's memory block may be different. In
this case, the environment pointer in COMMAND.COM's PSP contains
the segment of the environment block.
Once the memory block containing the environment is located,
we can directly manipulate the variables stored there.
Environment variables are stored in sequential order and are
terminated by NULs, exactly like strings in C. The end of the
valid data in the environment is indicated by a pair of
consecutive NULS. Each variable consists of a name (customarily
in upper case), and equal sign, and a text value.
MSTR_ENV.C (listing 1) is a module for C which directly
accesses the master environment. It contains three public
functions, m_getenv(), m_putenv(), and m_delenv(). A fourth
function, m_findenv() initializes the pointer to the master
environment. Whenever one of the public functions is called, it
checks a flag (initialized) to see if it is necessary to call
m_findenv(). This eliminates the need for an explicit call by an
application program to an initialization function, making the
programmer's task easier and less error-prone.
M_findenv() begins by invoking MS-DOS function 0x52. The
returned values in the ES and BX registers are then used to
construct a point to the segment address of the first MCB. The
first MCB is the one for the MS-DOS kernel and device drivers;
the second MCB is associated with COMMAND.COM. Using the formula
mentioned above for following the chain of MCBs, m_findenv()
finds the second MCB (for COMMAND.COM). That MCB contains the
segment of COMMAND.COM's PSP. Once the PSP has been located, the
environment pointer stored there is checked to see if it is 0. If
so, the environment is stored in the next consecutive memory
block above COMMAND.COM; otherwise, we have a segment address,
and can build a direct pointer to the master environment block.
Finally, m_findenv() calculates the